from PyQt4                          import QtCore
from PyQt4                          import QtGui
from sqlConnection.psqlConnections  import psqlConnections
from constants.constants            import DB_NAME
from constants.constants            import COLUMNS_CONFIGURATION
from constants.constants            import COLUMNS_MENU_CONF
from constants.constants            import COLUMNS_LAUNCH_CONFIG
from constants.constants            import COLUMNS_ACTION_LAUNCH
from constants.constants            import COLUMNS_SEPARATE_TRAY
from constants.constants            import TABLE_LAUNCH_CONFIGURATIONS
from constants.constants            import TABLE_ACTION_LAUNCH_REL
from constants.constants            import TABLE_NAME_MENU
from constants.constants            import TABLE_NAME_CONFIGURATIONS
from constants.constants            import TABLE_SEPARATE_TRAY   
from constants.constants            import DEFAULT_MENU_LIST
from constants.constants            import COLUMNS_BROWSER_SITES
from constants.constants            import TABLE_BROWSER_SITES
from constants.constants            import TABLE_STARTUP
from constants.constants            import COLUMNS_STARTUP
from constants.constants            import ICON_EXIT
from constants                      import constants
from Main.render_menu               import RenderMenu
from utils.utils                    import logMessage, launchMessage
from utils.utils                    import startUpEnable
from utils.utils                    import getExeFromPath
from utils.utils                    import getUsefulPath
from utils.utils                    import exceptionManagement
from utils.utils                    import getFileFromSystem
from utils.utils                    import launchTryIconMessage
from utils.utils                    import getIconsDirectory
from utils.utils                    import getModulePath
import json
import os
import logging
import time
import subprocess
import copy


class ExeThreadOtherTrayIcons(QtCore.QProcess):     
    def __init__(self, outFilePath, exeIconPath, exePath, exitIconPath, parent):    
        self.outFilePath = outFilePath
        self.exeIconPath = exeIconPath
        self.exePath = exePath
        self.exitIconPath = exitIconPath
        self.parent = parent
        return super(ExeThreadOtherTrayIcons, self).__init__()
    
    def start(self, program, arguments=[], mode=None):
        logging.info('[ExeThreadOtherTrayIcons] self.filePathToOpen = "%s"' % (self.outFilePath))
        try:
            exePath = os.path.join(getUsefulPath(), 'setup', 'dist', 'newPyFileExe.exe')
            toOpen = '"%s" "%s" "%s" "%s"' % (exePath, self.exeIconPath, self.exitIconPath, self.exePath)
            logging.debug('toOpen: %s' % (toOpen))
            if not os.path.exists(exePath):
                logging.warning('Path not exists %s' % (exePath))
            #subprocess.call(toOpen, shell=True)
            subprocess.Popen(toOpen, shell=True, stdin=None, stdout=None, stderr=None, close_fds=True)
        except Exception, ex:
            logMessage('error', ex)

    @QtCore.pyqtSlot()
    def readStdOutput(self):
        self.edit.append(QtCore.QString(self.readAllStandardOutput()))

class ExeThread(QtCore.QThread):
    def __init__(self, exePath):
        self.exePath = exePath
        super(ExeThread, self).__init__()
    
    def run(self, *args, **kwargs):
        #logging.info('[ExeThread] self.exePath = "%s"' % (self.exePath))
        exeList = getExeFromPath(self.exePath)
        resJson = json.dumps(exeList)
        dirPath = getUsefulPath()
        newName = os.path.basename(self.exePath)
        filePath = os.path.join(dirPath,'exe_list_%s.txt' % (newName))
        if os.path.exists(filePath):
            os.remove(filePath)
        target = open(filePath, 'w')
        target.write(resJson)
        target.close()
        logging.debug('[ExeThread] ended ExeThread of exe Path %r' % (self.exePath))
        return QtCore.QThread.run(self, *args, **kwargs)


class Manager(QtCore.QObject):
    
    def __init__(self, tryIcon):
        super(Manager, self).__init__()
        launchTryIconMessage('Tray Applications Manager Initialization Started', 'Starting Tray applications manager, loading stored datas.')
        self.tryIcon    = tryIcon
        self.dbInst     = None
        self.settings   = tryIcon.settings
        self.threads    = []
        self.trayThreads = []
        self.initDbConnection()
        self.loadThemeConfigs()
        self.setUpdateConstants()
        self.setUpdateStartup()
        self.setDefaultMenus()
        self.cleanPaths()
        self.launchChangeIcons()
        self.renderMenu = RenderMenu(self.dbInst, self.tryIcon, self.settings, self)
        self.launchSeparateTrayIcons()
        logging.info('getUsefulPath: %r' % (getUsefulPath()))
        logging.info('getModulePath: %r' % (getModulePath()))
        logging.info('getIconsDirectory: %r' % (getIconsDirectory()))
        launchTryIconMessage('Tray Applications Manager', 'Initialization is not finished but you can use the program.')
        
    def initDbConnection(self):
        try:
            #logMessage('debug', 'Manager started', 'initDbConnection')
            self.dbInst = psqlConnections()
            self.dbInst.setConnection(DB_NAME)
            
            self.dbInst.tableExistOrCreate(TABLE_ACTION_LAUNCH_REL,    COLUMNS_ACTION_LAUNCH)
            self.dbInst.tableExistOrCreate(TABLE_LAUNCH_CONFIGURATIONS,   COLUMNS_LAUNCH_CONFIG)
            self.dbInst.tableExistOrCreate(TABLE_NAME_MENU,      COLUMNS_MENU_CONF)
            self.dbInst.tableExistOrCreate(TABLE_NAME_CONFIGURATIONS,    COLUMNS_CONFIGURATION)
            self.dbInst.tableExistOrCreate(TABLE_BROWSER_SITES,  COLUMNS_BROWSER_SITES)
            self.dbInst.tableExistOrCreate(TABLE_STARTUP,  COLUMNS_STARTUP)
            self.dbInst.tableExistOrCreate(TABLE_SEPARATE_TRAY,  COLUMNS_SEPARATE_TRAY)
        except Exception,ex:
            exceptionManagement(ex, 'Some errors on db init!')

    def launchChangeIcons(self, force=False):
        checkForExe = True
        objConfig = self.dbInst.getRowsTable(TABLE_NAME_CONFIGURATIONS, ['config_value'], [('config_name', '=', 'STATUP_EXE_CHECK')])
        if objConfig:
            checkForExe = eval(objConfig[0].config_value)
        if checkForExe or force:
            self.clearExeLists()
            self.tryIcon.launchChangeIcons()
            self.computeExeList()

    def clearExeLists(self):
        usefulPath = getUsefulPath()
        files = os.listdir(usefulPath)
        for fileName in files:
            if fileName.startswith('exe_list_'):
                filePath = os.path.join(usefulPath, fileName)
                if os.path.exists(filePath):
                    os.remove(filePath)

    def computeExeList(self):
        objConfig = self.dbInst.getRowsTable(TABLE_NAME_CONFIGURATIONS, ['config_value'], [('config_name', '=', 'EXE_SEARCH_PATH')])
        if not objConfig or not objConfig[0].config_value:
            val = 'C:\\Program Files'
            exeThread = ExeThread(val)
            self.threads.append(exeThread)
            exeThread.start()
            return
        for obj in objConfig:
            values = eval(obj.config_value)
            for val in values:
                exeThread = ExeThread(val)
                self.threads.append(exeThread)
                exeThread.start()

    def setUpdateStartup(self):
        objs = self.dbInst.getRowsTable(TABLE_STARTUP, ['id','name','path'])
        for obj in objs:
            startUpEnable(obj.path, True)

    def setDefaultMenus(self):
        configSettingsObjs = self.dbInst.getRowsTable(TABLE_NAME_CONFIGURATIONS, ['config_value'], [('config_name', '=', 'USE_DEFAULT_MENU')])
        useDefaultMenus = False
        for confObj in configSettingsObjs:
            useDefaultMenus = eval(confObj.config_value)
        listToWrite = DEFAULT_MENU_LIST
        for rowDict in listToWrite:
            menu_name = rowDict.get('menu_name','')
            if useDefaultMenus == True or menu_name in ['Settings', 'Exit']:
                res = self.dbInst.search([('menu_name','=',menu_name)], TABLE_NAME_MENU)
                if not res:
                    self.dbInst.writeRow(rowDict,TABLE_NAME_MENU)
                else:
                    self.dbInst.updateRow(rowDict, TABLE_NAME_MENU, [('id','=',res[0])])
                
    def loadThemeConfigs(self):
        filterList = ['BACKGROUND_BASE', 'BACKGROUND_CANCEL_BUTTONBOX', 'BACKGROUND_MENU', 'BACKGROUND_MENU_BAR',
                      'BACKGROUND_OK_BUTTONBOX', 'BACKGROUND_TABLES', 'BACKGROUND_TABWIDGET', 'BACKGROUND_BUTTONS']
        objs = self.dbInst.getRowsTable(TABLE_NAME_CONFIGURATIONS, [], [('config_name', 'in', filterList)])
        for obj in objs:
            constants.__dict__[obj.config_name] = constants.getBImageStylesheet(obj.config_value)
        objs = self.dbInst.getRowsTable(TABLE_NAME_CONFIGURATIONS, [], [('config_name', '=', 'BUTTONS_FLAT')])
        for obj in objs:
            constants.__dict__[obj.config_name] = bool(obj.config_value)
        
    def setUpdateConstants(self):
        '''
        '''
        defaultSettingsInitList = constants.DEFAULT_CONFIG_LIST
        defaultSettingsInitListCopy = copy.deepcopy(defaultSettingsInitList)
        for settingDict in defaultSettingsInitListCopy:
            configIds = self.dbInst.search([('config_name', '=', settingDict.get('config_name'))], TABLE_NAME_CONFIGURATIONS)
            if not configIds:
                self.dbInst.writeRow(settingDict, TABLE_NAME_CONFIGURATIONS)
            else:
                if 'config_value' in settingDict:
                    del settingDict['config_value']
                self.dbInst.updateRow(settingDict, TABLE_NAME_CONFIGURATIONS, [('id', 'in', configIds)])

    def cleanPaths(self):
        menu_objects = self.dbInst.getRowsTable(TABLE_NAME_MENU, ['id', 'menu_name', 'exe_file_path'])
        for menu_obj in menu_objects:
            exe_file_path = menu_obj.exe_file_path
            if exe_file_path and not os.path.exists(exe_file_path):
                self.launchCleanDial(exe_file_path)
                newPath = ''
                if self.singleDialog.exec_() == QtGui.QDialog.Accepted:
                    newPath = unicode(self.lineEditPath.text())
                self.dbInst.updateRow({'exe_file_path': newPath}, TABLE_NAME_MENU, [('id', '=', menu_obj.id)])
        
        startup_objects = self.dbInst.getRowsTable(TABLE_STARTUP, ['id', 'name', 'path'])
        for startup_obj in startup_objects:
            exe_file_path = startup_obj.path
            if exe_file_path and not os.path.exists(exe_file_path):
                self.launchCleanDial(exe_file_path)
                newPath = ''
                if self.singleDialog.exec_() == QtGui.QDialog.Accepted:
                    newPath = unicode(self.lineEditPath.text())
                self.dbInst.updateRow({'path': newPath}, TABLE_STARTUP, [('id', '=', startup_obj.id)])
                startUpEnable(newPath, True)

    def launchCleanDial(self, exe_file_path):
        warningLabel = QtGui.QLabel('The following Path does not exists')
        self.singleDialog = QtGui.QDialog()
        self.singleDialog.setWindowIconText('Warning')
        gridLayout = QtGui.QGridLayout(self.singleDialog)
        verticalLayout = QtGui.QVBoxLayout()
        verticalLayout.addWidget(warningLabel)
        
        hlay = QtGui.QHBoxLayout()
        label = QtGui.QLabel('Action Path')
        self.lineEditPath = QtGui.QLineEdit()
        self.lineEditPath.setText(exe_file_path)
        pathButton = QtGui.QPushButton('...')
        pathButton.clicked[()].connect(lambda aaa=self.lineEditPath: self.getPath(aaa))
        hlay.addWidget(label)
        hlay.addWidget(self.lineEditPath)
        hlay.addWidget(pathButton)
        verticalLayout.addLayout(hlay)
        buttonBox = QtGui.QDialogButtonBox(self.singleDialog)
        buttonBox.setOrientation(QtCore.Qt.Horizontal)
        buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
        buttonBox.accepted.connect(self.acceptAskForm)
        buttonBox.rejected.connect(self.rejectAskForm)
        verticalLayout.addWidget(buttonBox)
        gridLayout.addLayout(verticalLayout, 0, 0, 1, 1)
                
    def acceptAskForm(self):
        self.singleDialog.accept()
    
    def rejectAskForm(self):
        self.singleDialog.reject()
    
    def getPath(self, singleWidget=None):
        if singleWidget:
            newPath = getFileFromSystem(desc='Open', startPath=singleWidget.text())
            if newPath:
                singleWidget.setText(newPath)

    def launchSeparateTrayIcons(self):
        logging.debug('[launchSeparateTrayIcons] started')
        for thread in self.trayThreads:
            thread.terminate()
        objs = self.dbInst.getRowsTable(TABLE_SEPARATE_TRAY, [], [('enabled', '=', True)])
        basePath = getUsefulPath()
        for obj in objs:
            exePath = obj.exe_path
            if not exePath:
                continue
            if not os.path.exists(exePath):
                message = '%s does not exists.' % exePath
                launchMessage(message)
                logMessage('warning', message, 'launchSeparateTrayIcons')
            fileName = 'newPyFileExe.py'
            exePath = exePath
            outFilePath = os.path.join(basePath, fileName)
            exeIconPath = obj.icon_path
            exitIconPath = os.path.join(getIconsDirectory(), ICON_EXIT)
            try:
                logging.debug('[launchSeparateTrayIcons] outFilePath = "%s"' % (outFilePath))
                exeProcess = ExeThreadOtherTrayIcons(outFilePath, exeIconPath, exePath, exitIconPath, self)
                exeProcess.setProcessChannelMode(QtCore.QProcess.MergedChannels)
                exeProcess.start("ldconfig -v")
                QtCore.QObject.connect(exeProcess, QtCore.SIGNAL("readyReadStandardOutput()"),exeProcess,QtCore.SLOT("readStdOutput()"))
                logging.debug('[launchSeparateTrayIcons] ended outFilePath = "%s"' % (outFilePath))
            except Exception, ex:
                logging.error(ex)
            time.sleep(0.2)
        logging.debug('[launchSeparateTrayIcons] ended')
        